home *** CD-ROM | disk | FTP | other *** search
- Subject: v17i078: Usenix/IEEE POSIX replacement for TAR and CPIO, Part05/06
- Newsgroups: comp.sources.unix
- Approved: rsalz@uunet.UU.NET
-
- Submitted-by: Mark H. Colburn <mark@jhereg.jhereg.mn.org>
- Posting-number: Volume 17, Issue 78
- Archive-name: pax/part05
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then unpack
- # it by saving it into a file and typing "sh file". To overwrite existing
- # files, type "sh file -c". You can also feed this as standard input via
- # unshar, or by typing "sh <file", e.g.. If this archive is complete, you
- # will see the following message at the end:
- # "End of archive 5 (of 6)."
- # Contents: buffer.c paxdir.c
- # Wrapped by mark@jhereg on Tue Dec 27 19:37:59 1988
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test -f buffer.c -a "${1}" != "-c" ; then
- echo shar: Will not over-write existing file \"buffer.c\"
- else
- echo shar: Extracting \"buffer.c\" \(17360 characters\)
- sed "s/^X//" >buffer.c <<'END_OF_buffer.c'
- X/* $Source: /u/mark/src/pax/RCS/buffer.c,v $
- X *
- X * $Revision: 1.1 $
- X *
- X * buffer.c - Buffer management functions
- X *
- X * DESCRIPTION
- X *
- X * These functions handle buffer manipulations for the archiving
- X * formats. Functions are provided to get memory for buffers,
- X * flush buffers, read and write buffers and de-allocate buffers.
- X * Several housekeeping functions are provided as well to get some
- X * information about how full buffers are, etc.
- X *
- X * AUTHOR
- X *
- X * Mark H. Colburn, NAPS International (mark@jhereg.mn.org)
- X *
- X * Sponsored by The USENIX Association for public distribution.
- X *
- X * Copyright (c) 1989 Mark H. Colburn.
- X * All rights reserved.
- X *
- X * Redistribution and use in source and binary forms are permitted
- X * provided that the above copyright notice is duplicated in all such
- X * forms and that any documentation, advertising materials, and other
- X * materials related to such distribution and use acknowledge that the
- X * software was developed * by Mark H. Colburn and sponsored by The
- X * USENIX Association.
- X *
- X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- X * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
- X *
- X * $Log: buffer.c,v $
- X * Revision 1.1 88/12/23 18:02:01 mark
- X * Initial revision
- X *
- X */
- X
- X#ifndef lint
- Xstatic char *ident = "$Id: buffer.c,v 1.1 88/12/23 18:02:01 mark Rel $";
- Xstatic char *copyright = "Copyright (c) 1989 Mark H. Colburn.\nAll rights reserved.\n";
- X#endif /* ! lint */
- X
- X
- X/* Headers */
- X
- X#include "pax.h"
- X
- X
- X/* Function Prototypes */
- X
- X#ifdef __STDC__
- X
- Xstatic int ar_write(int, char *, uint);
- Xstatic void buf_pad(OFFSET);
- Xstatic int indata(int, OFFSET, char *);
- Xstatic void outflush(void);
- Xstatic void buf_use(uint);
- Xstatic int buf_in_avail(char **, uint *);
- Xstatic uint buf_out_avail(char **);
- X
- X#else /* !__STDC__ */
- X
- Xstatic int ar_write();
- Xstatic void buf_pad();
- Xstatic int indata();
- Xstatic void outflush();
- Xstatic void buf_use();
- Xstatic int buf_in_avail();
- Xstatic uint buf_out_avail();
- X
- X#endif /* __STDC__ */
- X
- X
- X/* inentry - install a single archive entry
- X *
- X * DESCRIPTION
- X *
- X * Inentry reads an archive entry from the archive file and writes it
- X * out the the named file. If we are in PASS mode during archive
- X * processing, the pass() function is called, otherwise we will
- X * extract from the archive file.
- X *
- X * Inentry actaully calls indata to process the actual data to the
- X * file.
- X *
- X * PARAMETERS
- X *
- X * char *name - name of the file to extract from the archive
- X * Stat *asb - stat block of the file to be extracted from the
- X * archive.
- X *
- X * RETURNS
- X *
- X * Returns zero if successful, -1 otherwise.
- X */
- X
- X#ifdef __STDC__
- X
- Xint inentry(char *name, Stat *asb)
- X
- X#else
- X
- Xint inentry(name, asb)
- Xchar *name;
- XStat *asb;
- X
- X#endif
- X{
- X Link *linkp;
- X int ifd;
- X int ofd;
- X time_t tstamp[2];
- X
- X if ((ofd = openo(name, asb, linkp = linkfrom(name, asb), 0)) > 0) {
- X if (asb->sb_size || linkp == NULL || linkp->l_size == 0) {
- X close(indata(ofd, asb->sb_size, name));
- X } else if ((ifd = open(linkp->l_path->p_name, O_RDONLY)) < 0) {
- X warn(linkp->l_path->p_name, syserr());
- X } else {
- X passdata(linkp->l_path->p_name, ifd, name, ofd);
- X close(ifd);
- X close(ofd);
- X }
- X } else {
- X return(buf_skip((OFFSET) asb->sb_size) >= 0);
- X }
- X tstamp[0] = (!f_pass && f_access_time) ? asb->sb_atime : time((time_t *) 0);
- X tstamp[1] = f_modification_time ? asb->sb_mtime : time((time_t *) 0);
- X utime(name, tstamp);
- X return (0);
- X}
- X
- X
- X/* outdata - write archive data
- X *
- X * DESCRIPTION
- X *
- X * Outdata transfers data from the named file to the archive buffer.
- X * It knows about the file padding which is required by tar, but no
- X * by cpio. Outdata continues after file read errors, padding with
- X * null characters if neccessary. Closes the input file descriptor
- X * when finished.
- X *
- X * PARAMETERS
- X *
- X * int fd - file descriptor of file to read data from
- X * char *name - name of file
- X * OFFSET size - size of the file
- X *
- X */
- X
- X#ifdef __STDC__
- X
- Xvoid outdata(int fd, char *name, OFFSET size)
- X
- X#else
- X
- Xvoid outdata(fd, name, size)
- Xint fd;
- Xchar *name;
- XOFFSET size;
- X
- X#endif
- X{
- X uint chunk;
- X int got;
- X int oops;
- X uint avail;
- X int pad;
- X char *buf;
- X
- X oops = got = 0;
- X if (pad = (size % BLOCKSIZE)) {
- X pad = (BLOCKSIZE - pad);
- X }
- X while (size) {
- X avail = buf_out_avail(&buf);
- X size -= (chunk = size < avail ? (uint) size : avail);
- X if (oops == 0 && (got = read(fd, buf, (unsigned int) chunk)) < 0) {
- X oops = -1;
- X warn(name, syserr());
- X got = 0;
- X }
- X if (got < chunk) {
- X if (oops == NULL) {
- X oops = -1;
- X }
- X warn(name, "Early EOF");
- X while (got < chunk) {
- X buf[got++] = '\0';
- X }
- X }
- X buf_use(chunk);
- X }
- X close(fd);
- X if (ar_format == TAR) {
- X buf_pad((OFFSET) pad);
- X }
- X}
- X
- X
- X/* write_eot - write the end of archive record(s)
- X *
- X * DESCRIPTION
- X *
- X * Write out an End-Of-Tape record. We actually zero at least one
- X * record, through the end of the block. Old tar writes garbage after
- X * two zeroed records -- and PDtar used to.
- X */
- X
- X#ifdef __STDC__
- X
- Xvoid write_eot(void)
- X
- X#else
- X
- Xvoid write_eot()
- X
- X#endif
- X{
- X OFFSET pad;
- X char header[M_STRLEN + H_STRLEN + 1];
- X
- X if (ar_format == TAR) {
- X /* write out two zero blocks for trailer */
- X pad = 2 * BLOCKSIZE;
- X } else {
- X if (pad = (total + M_STRLEN + H_STRLEN + TRAILZ) % BLOCKSIZE) {
- X pad = BLOCKSIZE - pad;
- X }
- X strcpy(header, M_ASCII);
- X sprintf(header + M_STRLEN, H_PRINT, 0, 0,
- X 0, 0, 0, 1, 0, (time_t) 0, TRAILZ, pad);
- X outwrite(header, M_STRLEN + H_STRLEN);
- X outwrite(TRAILER, TRAILZ);
- X }
- X buf_pad((OFFSET) pad);
- X outflush();
- X}
- X
- X
- X/* outwrite - write archive data
- X *
- X * DESCRIPTION
- X *
- X * Writes out data in the archive buffer to the archive file. The
- X * buffer index and the total byte count are incremented by the number
- X * of data bytes written.
- X *
- X * PARAMETERS
- X *
- X * char *idx - pointer to data to write
- X * uint len - length of the data to write
- X */
- X
- X#ifdef __STDC__
- X
- Xvoid outwrite(char *idx, uint len)
- X
- X#else
- X
- Xvoid outwrite(idx, len)
- Xchar *idx; /* pointer to data to write */
- Xuint len; /* length of data to write */
- X
- X#endif
- X{
- X uint have;
- X uint want;
- X char *endx;
- X
- X endx = idx + len;
- X while (want = endx - idx) {
- X if (bufend - bufidx < 0) {
- X fatal("Buffer overlow in out_write\n");
- X }
- X if ((have = bufend - bufidx) == 0) {
- X outflush();
- X }
- X if (have > want) {
- X have = want;
- X }
- X memcpy(bufidx, idx, (int) have);
- X bufidx += have;
- X idx += have;
- X total += have;
- X }
- X}
- X
- X
- X/* passdata - copy data to one file
- X *
- X * DESCRIPTION
- X *
- X * Copies a file from one place to another. Doesn't believe in input
- X * file descriptor zero (see description of kludge in openi() comments).
- X * Closes the provided output file descriptor.
- X *
- X * PARAMETERS
- X *
- X * char *from - input file name (old file)
- X * int ifd - input file descriptor
- X * char *to - output file name (new file)
- X * int ofd - output file descriptor
- X */
- X
- X#ifdef __STDC__
- X
- Xvoid passdata(char *from, int ifd, char *to, int ofd)
- X
- X#else
- X
- Xvoid passdata(from, ifd, to, ofd)
- Xchar *from;
- Xint ifd;
- Xchar *to;
- Xint ofd;
- X
- X#endif
- X{
- X int got;
- X int sparse;
- X char block[BUFSIZ];
- X
- X if (ifd) {
- X lseek(ifd, (OFFSET) 0, 0);
- X sparse = 0;
- X while ((got = read(ifd, block, sizeof(block))) > 0
- X && (sparse = ar_write(ofd, block, (uint) got)) >= 0) {
- X total += got;
- X }
- X if (got) {
- X warn(got < 0 ? from : to, syserr());
- X } else if (sparse > 0
- X && (lseek(ofd, (OFFSET)(-sparse), 1) < 0
- X || write(ofd, block, (uint) sparse) != sparse)) {
- X warn(to, syserr());
- X }
- X }
- X close(ofd);
- X}
- X
- X
- X/* buf_allocate - get space for the I/O buffer
- X *
- X * DESCRIPTION
- X *
- X * buf_allocate allocates an I/O buffer using malloc. The resulting
- X * buffer is used for all data buffering throughout the program.
- X * Buf_allocate must be called prior to any use of the buffer or any
- X * of the buffering calls.
- X *
- X * PARAMETERS
- X *
- X * int size - size of the I/O buffer to request
- X *
- X * ERRORS
- X *
- X * If an invalid size is given for a buffer or if a buffer of the
- X * required size cannot be allocated, then the function prints out an
- X * error message and returns a non-zero exit status to the calling
- X * process, terminating the program.
- X *
- X */
- X
- X#ifdef __STDC__
- X
- Xvoid buf_allocate(OFFSET size)
- X
- X#else
- X
- Xvoid buf_allocate(size)
- XOFFSET size;
- X
- X#endif
- X{
- X extern char *malloc();
- X
- X if (size <= 0) {
- X fatal("invalid value for blocksize");
- X }
- X if ((bufstart = malloc((unsigned) size)) == NULL) {
- X fatal("Cannot allocate I/O buffer");
- X }
- X bufend = bufidx = bufstart;
- X bufend += size;
- X}
- X
- X
- X/* buf_skip - skip input archive data
- X *
- X * DESCRIPTION
- X *
- X * Buf_skip skips past archive data. It is used when the length of
- X * the archive data is known, and we do not wish to process the data.
- X *
- X * PARAMETERS
- X *
- X * OFFSET len - number of bytes to skip
- X *
- X * RETURNS
- X *
- X * Returns zero under normal circumstances, -1 if unreadable data is
- X * encountered.
- X */
- X
- X#ifdef __STDC__
- X
- Xint buf_skip(OFFSET len)
- X
- X#else
- X
- Xint buf_skip(len)
- XOFFSET len;
- X
- X#endif
- X{
- X uint chunk;
- X int corrupt = 0;
- X
- X while (len) {
- X if (bufend - bufidx < 0) {
- X fatal("Buffer overlow in buf_skip\n");
- X }
- X while ((chunk = bufend - bufidx) == 0) {
- X corrupt |= ar_read();
- X }
- X if (chunk > len) {
- X chunk = len;
- X }
- X bufidx += chunk;
- X len -= chunk;
- X total += chunk;
- X }
- X return (corrupt);
- X}
- X
- X
- X/* buf_read - read a given number of characters from the input archive
- X *
- X * DESCRIPTION
- X *
- X * Reads len number of characters from the input archive and
- X * stores them in the buffer pointed at by dst.
- X *
- X * PARAMETERS
- X *
- X * char *dst - pointer to buffer to store data into
- X * uint len - length of data to read
- X *
- X * RETURNS
- X *
- X * Returns zero with valid data, -1 if unreadable portions were
- X * replaced by null characters.
- X */
- X
- X#ifdef __STDC__
- X
- Xint buf_read(char *dst, uint len)
- X
- X#else
- X
- Xint buf_read(dst, len)
- Xchar *dst;
- Xuint len;
- X
- X#endif
- X{
- X int have;
- X int want;
- X int corrupt = 0;
- X char *endx = dst + len;
- X
- X while (want = endx - dst) {
- X if (bufend - bufidx < 0) {
- X fatal("Buffer overlow in buf_read\n");
- X }
- X while ((have = bufend - bufidx) == 0) {
- X have = 0;
- X corrupt |= ar_read();
- X }
- X if (have > want) {
- X have = want;
- X }
- X memcpy(dst, bufidx, have);
- X bufidx += have;
- X dst += have;
- X total += have;
- X }
- X return (corrupt);
- X}
- X
- X
- X/* indata - install data from an archive
- X *
- X * DESCRIPTION
- X *
- X * Indata writes size bytes of data from the archive buffer to the output
- X * file specified by fd. The filename which is being written, pointed
- X * to by name is provided only for diagnostics.
- X *
- X * PARAMETERS
- X *
- X * int fd - output file descriptor
- X * OFFSET size - number of bytes to write to output file
- X * char *name - name of file which corresponds to fd
- X *
- X * RETURNS
- X *
- X * Returns given file descriptor.
- X */
- X
- X#ifdef __STDC__
- X
- Xstatic int indata(int fd, OFFSET size, char *name)
- X
- X#else
- X
- Xstatic int indata(fd, size, name)
- Xint fd;
- XOFFSET size;
- Xchar *name;
- X
- X#endif
- X{
- X uint chunk;
- X char *oops;
- X int sparse;
- X int corrupt;
- X char *buf;
- X uint avail;
- X
- X corrupt = sparse = 0;
- X oops = NULL;
- X while (size) {
- X corrupt |= buf_in_avail(&buf, &avail);
- X size -= (chunk = size < avail ? (uint) size : avail);
- X if (oops == NULL && (sparse = ar_write(fd, buf, chunk)) < 0) {
- X oops = syserr();
- X }
- X buf_use(chunk);
- X }
- X if (corrupt) {
- X warn(name, "Corrupt archive data");
- X }
- X if (oops) {
- X warn(name, oops);
- X } else if (sparse > 0 && (lseek(fd, (OFFSET) - 1, 1) < 0
- X || write(fd, "", 1) != 1)) {
- X warn(name, syserr());
- X }
- X return (fd);
- X}
- X
- X
- X/* outflush - flush the output buffer
- X *
- X * DESCRIPTION
- X *
- X * The output buffer is written, if there is anything in it, to the
- X * archive file.
- X */
- X
- X#ifdef __STDC__
- X
- Xstatic void outflush(void)
- X
- X#else
- X
- Xstatic void outflush()
- X
- X#endif
- X{
- X char *buf;
- X int got;
- X uint len;
- X
- X /* if (bufidx - buf > 0) */
- X for (buf = bufstart; len = bufidx - buf;) {
- X if ((got = write(archivefd, buf, MIN(len, blocksize))) > 0) {
- X buf += got;
- X } else if (got < 0) {
- X next(AR_WRITE);
- X }
- X }
- X bufend = (bufidx = bufstart) + blocksize;
- X}
- X
- X
- X/* ar_read - fill the archive buffer
- X *
- X * DESCRIPTION
- X *
- X * Remembers mid-buffer read failures and reports them the next time
- X * through. Replaces unreadable data with null characters. Resets
- X * the buffer pointers as appropriate.
- X *
- X * RETURNS
- X *
- X * Returns zero with valid data, -1 otherwise.
- X */
- X
- X#ifdef __STDC__
- X
- Xint ar_read(void)
- X
- X#else
- X
- Xint ar_read()
- X
- X#endif
- X{
- X int got;
- X static int failed;
- X
- X bufend = bufidx = bufstart;
- X if (!failed) {
- X if (areof) {
- X if (total == 0) {
- X fatal("No input");
- X } else {
- X next(AR_READ);
- X }
- X }
- X while (!failed && !areof && bufstart + blocksize - bufend >= blocksize) {
- X if ((got = read(archivefd, bufend, (unsigned int) blocksize)) > 0) {
- X bufend += got;
- X } else if (got < 0) {
- X failed = -1;
- X warnarch(syserr(), (OFFSET) 0 - (bufend - bufidx));
- X } else {
- X ++areof;
- X }
- X }
- X }
- X if (failed && bufend == bufstart) {
- X failed = 0;
- X for (got = 0; got < blocksize; ++got) {
- X *bufend++ = '\0';
- X }
- X return (-1);
- X }
- X return (0);
- X}
- X
- X
- X/* ar_write - write a filesystem block
- X *
- X * DESCRIPTION
- X *
- X * Writes len bytes of data data from the specified buffer to the
- X * specified file. Seeks past sparse blocks.
- X *
- X * PARAMETERS
- X *
- X * int fd - file to write to
- X * char *buf - buffer to get data from
- X * uint len - number of bytes to transfer
- X *
- X * RETURNS
- X *
- X * Returns 0 if the block was written, the given length for a sparse
- X * block or -1 if unsuccessful.
- X */
- X
- X#ifdef __STDC__
- X
- Xstatic int ar_write(int fd, char *buf, uint len)
- X
- X#else
- X
- Xstatic int ar_write(fd, buf, len)
- Xint fd;
- Xchar *buf;
- Xuint len;
- X
- X#endif
- X{
- X char *bidx;
- X char *bend;
- X
- X bend = (bidx = buf) + len;
- X while (bidx < bend) {
- X if (*bidx++) {
- X return (write(fd, buf, len) == len ? 0 : -1);
- X }
- X }
- X return (lseek(fd, (OFFSET) len, 1) < 0 ? -1 : len);
- X}
- X
- X
- X/* buf_pad - pad the archive buffer
- X *
- X * DESCRIPTION
- X *
- X * Buf_pad writes len zero bytes to the archive buffer in order to
- X * pad it.
- X *
- X * PARAMETERS
- X *
- X * OFFSET pad - number of zero bytes to pad
- X *
- X */
- X
- X#ifdef __STDC__
- X
- Xstatic void buf_pad(OFFSET pad)
- X
- X#else
- X
- Xstatic void buf_pad(pad)
- XOFFSET pad;
- X
- X#endif
- X{
- X int idx;
- X int have;
- X
- X while (pad) {
- X if ((have = bufend - bufidx) > pad) {
- X have = pad;
- X }
- X for (idx = 0; idx < have; ++idx) {
- X *bufidx++ = '\0';
- X }
- X total += have;
- X pad -= have;
- X if (bufend - bufidx == 0) {
- X outflush();
- X }
- X }
- X}
- X
- X
- X/* buf_use - allocate buffer space
- X *
- X * DESCRIPTION
- X *
- X * Buf_use marks space in the buffer as being used; advancing both the
- X * buffer index (bufidx) and the total byte count (total).
- X *
- X * PARAMETERS
- X *
- X * uint len - Amount of space to allocate in the buffer
- X */
- X
- X#ifdef __STDC__
- X
- Xstatic void buf_use(uint len)
- X
- X#else
- X
- Xstatic void buf_use(len)
- Xuint len;
- X
- X#endif
- X{
- X bufidx += len;
- X total += len;
- X}
- X
- X
- X/* buf_in_avail - index available input data within the buffer
- X *
- X * DESCRIPTION
- X *
- X * Buf_in_avail fills the archive buffer, and points the bufp
- X * parameter at the start of the data. The lenp parameter is
- X * modified to contain the number of bytes which were read.
- X *
- X * PARAMETERS
- X *
- X * char **bufp - pointer to the buffer to read data into
- X * uint *lenp - pointer to the number of bytes which were read
- X * (returned to the caller)
- X *
- X * RETURNS
- X *
- X * Stores a pointer to the data and its length in given locations.
- X * Returns zero with valid data, -1 if unreadable portions were
- X * replaced with nulls.
- X *
- X * ERRORS
- X *
- X * If an error occurs in ar_read, the error code is returned to the
- X * calling function.
- X *
- X */
- X
- X#ifdef __STDC__
- X
- Xstatic int buf_in_avail(char **bufp, uint *lenp)
- X
- X#else
- X
- Xstatic int buf_in_avail(bufp, lenp)
- Xchar **bufp;
- Xuint *lenp;
- X
- X#endif
- X{
- X uint have;
- X int corrupt = 0;
- X
- X while ((have = bufend - bufidx) == 0) {
- X corrupt |= ar_read();
- X }
- X *bufp = bufidx;
- X *lenp = have;
- X return (corrupt);
- X}
- X
- X
- X/* buf_out_avail - index buffer space for archive output
- X *
- X * DESCRIPTION
- X *
- X * Stores a buffer pointer at a given location. Returns the number
- X * of bytes available.
- X *
- X * PARAMETERS
- X *
- X * char **bufp - pointer to the buffer which is to be stored
- X *
- X * RETURNS
- X *
- X * The number of bytes which are available in the buffer.
- X *
- X */
- X
- X#ifdef __STDC__
- X
- Xstatic uint buf_out_avail(char **bufp)
- X
- X#else
- X
- Xstatic uint buf_out_avail(bufp)
- Xchar **bufp;
- X
- X#endif
- X{
- X int have;
- X
- X if (bufend - bufidx < 0) {
- X fatal("Buffer overlow in buf_out_avail\n");
- X }
- X if ((have = bufend - bufidx) == 0) {
- X outflush();
- X }
- X *bufp = bufidx;
- X return (have);
- X}
- END_OF_buffer.c
- if test 17360 -ne `wc -c <buffer.c`; then
- echo shar: \"buffer.c\" unpacked with wrong size!
- fi
- # end of overwriting check
- fi
- if test -f paxdir.c -a "${1}" != "-c" ; then
- echo shar: Will not over-write existing file \"paxdir.c\"
- else
- echo shar: Extracting \"paxdir.c\" \(16936 characters\)
- sed "s/^X//" >paxdir.c <<'END_OF_paxdir.c'
- X/*
- X opendir -- open a directory stream
- X
- X last edit: 16-Jun-1987 D A Gwyn
- X*/
- X
- X#include <sys/errno.h>
- X#include <sys/types.h>
- X#include <sys/stat.h>
- X#include "paxdir.h"
- X
- X#ifdef BSD_SYSV
- X/*
- X <sys/_dir.h> -- definitions for 4.2,4.3BSD directories
- X
- X last edit: 25-Apr-1987 D A Gwyn
- X
- X A directory consists of some number of blocks of DIRBLKSIZ bytes each,
- X where DIRBLKSIZ is chosen such that it can be transferred to disk in a
- X single atomic operation (e.g., 512 bytes on most machines).
- X
- X Each DIRBLKSIZ-byte block contains some number of directory entry
- X structures, which are of variable length. Each directory entry has the
- X beginning of a (struct direct) at the front of it, containing its
- X filesystem-unique ident number, the length of the entry, and the length
- X of the name contained in the entry. These are followed by the NUL-
- X terminated name padded to a (long) boundary with 0 bytes. The maximum
- X length of a name in a directory is MAXNAMELEN.
- X
- X The macro DIRSIZ(dp) gives the amount of space required to represent a
- X directory entry. Free space in a directory is represented by entries
- X that have dp->d_reclen > DIRSIZ(dp). All DIRBLKSIZ bytes in a
- X directory block are claimed by the directory entries; this usually
- X results in the last entry in a directory having a large dp->d_reclen.
- X When entries are deleted from a directory, the space is returned to the
- X previous entry in the same directory block by increasing its
- X dp->d_reclen. If the first entry of a directory block is free, then
- X its dp->d_fileno is set to 0; entries other than the first in a
- X directory do not normally have dp->d_fileno set to 0.
- X
- X prerequisite: <sys/types.h>
- X*/
- X
- X#if defined(accel) || defined(sun) || defined(vax)
- X#define DIRBLKSIZ 512 /* size of directory block */
- X#else
- X#ifdef alliant
- X#define DIRBLKSIZ 4096 /* size of directory block */
- X#else
- X#ifdef gould
- X#define DIRBLKSIZ 1024 /* size of directory block */
- X#else
- X#ifdef ns32000 /* Dynix System V */
- X#define DIRBLKSIZ 2600 /* size of directory block */
- X#else /* be conservative; multiple blocks are okay
- X * but fractions are not */
- X#define DIRBLKSIZ 4096 /* size of directory block */
- X#endif
- X#endif
- X#endif
- X#endif
- X
- X#define MAXNAMELEN 255 /* maximum filename length */
- X/* NOTE: not MAXNAMLEN, which has been preempted by SVR3 <dirent.h> */
- X
- Xstruct direct { /* data from read()/_getdirentries() */
- X unsigned long d_fileno; /* unique ident of entry */
- X unsigned short d_reclen; /* length of this record */
- X unsigned short d_namlen; /* length of string in d_name */
- X char d_name[MAXNAMELEN + 1]; /* NUL-terminated filename */
- X};
- X
- X/*
- X The DIRSIZ macro gives the minimum record length which will hold the
- X directory entry. This requires the amount of space in a (struct
- X direct) without the d_name field, plus enough space for the name with a
- X terminating NUL character, rounded up to a (long) boundary.
- X
- X (Note that Berkeley didn't properly compensate for struct padding,
- X but we nevertheless have to use the same size as the actual system.)
- X*/
- X
- X#define DIRSIZ( dp ) ((sizeof(struct direct) - (MAXNAMELEN+1) \
- X + sizeof(long) + (dp)->d_namlen) \
- X / sizeof(long) * sizeof(long))
- X
- X#else
- X#include <sys/dir.h>
- X#ifdef SYSV3
- X#undef MAXNAMLEN /* avoid conflict with SVR3 */
- X#endif
- X /* Good thing we don't need to use the DIRSIZ() macro! */
- X#ifdef d_ino /* 4.3BSD/NFS using d_fileno */
- X#undef d_ino /* (not absolutely necessary) */
- X#else
- X#define d_fileno d_ino /* (struct direct) member */
- X#endif
- X#endif
- X#ifdef UNK
- X#ifndef UFS
- X#include "***** ERROR ***** UNK applies only to UFS"
- X/* One could do something similar for getdirentries(), but I didn't bother. */
- X#endif
- X#include <signal.h>
- X#endif
- X
- X#if defined(UFS) + defined(BFS) + defined(NFS) != 1 /* sanity check */
- X#include "***** ERROR ***** exactly one of UFS, BFS, or NFS must be defined"
- X#endif
- X
- X#ifdef UFS
- X#define RecLen( dp ) (sizeof(struct direct)) /* fixed-length entries */
- X#else /* BFS || NFS */
- X#define RecLen( dp ) ((dp)->d_reclen) /* variable-length entries */
- X#endif
- X
- X#ifdef NFS
- X#ifdef BSD_SYSV
- X#define getdirentries _getdirentries /* package hides this system call */
- X#endif
- Xextern int getdirentries();
- Xstatic long dummy; /* getdirentries() needs basep */
- X#define GetBlock( fd, buf, n ) getdirentries( fd, buf, (unsigned)n, &dummy )
- X#else /* UFS || BFS */
- X#ifdef BSD_SYSV
- X#define read _read /* avoid emulation overhead */
- X#endif
- Xextern int read();
- X#define GetBlock( fd, buf, n ) read( fd, buf, (unsigned)n )
- X#endif
- X
- X#ifdef UNK
- Xextern int _getdents(); /* actual system call */
- X#endif
- X
- Xextern char *strncpy();
- Xextern int fstat();
- Xextern OFFSET lseek();
- X
- Xextern int errno;
- X
- X#ifndef DIRBLKSIZ
- X#define DIRBLKSIZ 4096 /* directory file read buffer size */
- X#endif
- X
- X#ifndef NULL
- X#define NULL 0
- X#endif
- X
- X#ifndef SEEK_CUR
- X#define SEEK_CUR 1
- X#endif
- X
- X#ifndef S_ISDIR /* macro to test for directory file */
- X#define S_ISDIR( mode ) (((mode) & S_IFMT) == S_IFDIR)
- X#endif
- X
- X
- X#ifndef SEEK_CUR
- X#define SEEK_CUR 1
- X#endif
- X
- X#ifdef BSD_SYSV
- X#define open _open /* avoid emulation overhead */
- X#endif
- X
- Xextern int getdents(); /* SVR3 system call, or emulation */
- X
- Xtypedef char *pointer; /* (void *) if you have it */
- X
- Xextern void free();
- Xextern pointer malloc();
- Xextern int
- Xopen(), close(), fstat();
- X
- Xextern int errno;
- Xextern OFFSET lseek();
- X
- X#ifndef SEEK_SET
- X#define SEEK_SET 0
- X#endif
- X
- Xtypedef int bool; /* Boolean data type */
- X#define false 0
- X#define true 1
- X
- X
- X#ifndef NULL
- X#define NULL 0
- X#endif
- X
- X#ifndef O_RDONLY
- X#define O_RDONLY 0
- X#endif
- X
- X#ifndef S_ISDIR /* macro to test for directory file */
- X#define S_ISDIR( mode ) (((mode) & S_IFMT) == S_IFDIR)
- X#endif
- X
- X#ifdef __STDC__
- X
- XDIR *opendir(char *dirname)
- X
- X#else
- X
- XDIR *opendir(dirname)
- Xchar *dirname; /* name of directory */
- X
- X#endif
- X{
- X register DIR *dirp; /* -> malloc'ed storage */
- X register int fd; /* file descriptor for read */
- X struct stat sbuf; /* result of fstat() */
- X
- X if ((fd = open(dirname, O_RDONLY)) < 0)
- X return NULL; /* errno set by open() */
- X
- X if (fstat(fd, &sbuf) != 0 || !S_ISDIR(sbuf.st_mode)) {
- X close(fd);
- X errno = ENOTDIR;
- X return NULL; /* not a directory */
- X }
- X if ((dirp = (DIR *) malloc(sizeof(DIR))) == NULL
- X || (dirp->dd_buf = (char *) malloc((unsigned) DIRBUF)) == NULL
- X ) {
- X register int serrno = errno;
- X /* errno set to ENOMEM by sbrk() */
- X
- X if (dirp != NULL)
- X free((pointer) dirp);
- X
- X close(fd);
- X errno = serrno;
- X return NULL; /* not enough memory */
- X }
- X dirp->dd_fd = fd;
- X dirp->dd_loc = dirp->dd_size = 0; /* refill needed */
- X
- X return dirp;
- X}
- X
- X
- X/*
- X * closedir -- close a directory stream
- X *
- X * last edit: 11-Nov-1988 D A Gwyn
- X */
- X
- X#ifdef __STDC__
- X
- Xint closedir(register DIR *dirp)
- X
- X#else
- X
- Xint closedir(dirp)
- Xregister DIR *dirp; /* stream from opendir() */
- X
- X#endif
- X{
- X register int fd;
- X
- X if ( dirp == NULL || dirp->dd_buf == NULL ) {
- X errno = EFAULT;
- X return -1; /* invalid pointer */
- X }
- X
- X fd = dirp->dd_fd; /* bug fix thanks to R. Salz */
- X free( (pointer)dirp->dd_buf );
- X free( (pointer)dirp );
- X return close( fd );
- X}
- X
- X
- X/*
- X readdir -- read next entry from a directory stream
- X
- X last edit: 25-Apr-1987 D A Gwyn
- X*/
- X
- X#ifdef __STDC__
- X
- Xstruct dirent *readdir(register DIR *dirp)
- X
- X#else
- X
- Xstruct dirent *readdir(dirp)
- Xregister DIR *dirp; /* stream from opendir() */
- X
- X#endif
- X{
- X register struct dirent *dp; /* -> directory data */
- X
- X if (dirp == NULL || dirp->dd_buf == NULL) {
- X errno = EFAULT;
- X return NULL; /* invalid pointer */
- X }
- X do {
- X if (dirp->dd_loc >= dirp->dd_size) /* empty or obsolete */
- X dirp->dd_loc = dirp->dd_size = 0;
- X
- X if (dirp->dd_size == 0 /* need to refill buffer */
- X && (dirp->dd_size =
- X getdents(dirp->dd_fd, dirp->dd_buf, (unsigned) DIRBUF)
- X ) <= 0
- X )
- X return NULL; /* EOF or error */
- X
- X dp = (struct dirent *) & dirp->dd_buf[dirp->dd_loc];
- X dirp->dd_loc += dp->d_reclen;
- X }
- X while (dp->d_ino == 0L); /* don't rely on getdents() */
- X
- X return dp;
- X}
- X
- X
- X/*
- X seekdir -- reposition a directory stream
- X
- X last edit: 24-May-1987 D A Gwyn
- X
- X An unsuccessful seekdir() will in general alter the current
- X directory position; beware.
- X
- X NOTE: 4.nBSD directory compaction makes seekdir() & telldir()
- X practically impossible to do right. Avoid using them!
- X*/
- X
- X#ifdef __STDC__
- X
- Xvoid seekdir(register DIR *dirp, register OFFSET loc)
- X
- X#else
- X
- Xvoid seekdir(dirp, loc)
- Xregister DIR *dirp; /* stream from opendir() */
- Xregister OFFSET loc; /* position from telldir() */
- X
- X#endif
- X{
- X register bool rewind; /* "start over when stymied" flag */
- X
- X if (dirp == NULL || dirp->dd_buf == NULL) {
- X errno = EFAULT;
- X return; /* invalid pointer */
- X }
- X /*
- X * A (struct dirent)'s d_off is an invented quantity on 4.nBSD
- X * NFS-supporting systems, so it is not safe to lseek() to it.
- X */
- X
- X /* Monotonicity of d_off is heavily exploited in the following. */
- X
- X /*
- X * This algorithm is tuned for modest directory sizes. For huge
- X * directories, it might be more efficient to read blocks until the first
- X * d_off is too large, then back up one block, or even to use binary
- X * search on the directory blocks. I doubt that the extra code for that
- X * would be worthwhile.
- X */
- X
- X if (dirp->dd_loc >= dirp->dd_size /* invalid index */
- X || ((struct dirent *) & dirp->dd_buf[dirp->dd_loc])->d_off > loc
- X /* too far along in buffer */
- X )
- X dirp->dd_loc = 0; /* reset to beginning of buffer */
- X /* else save time by starting at current dirp->dd_loc */
- X
- X for (rewind = true;;) {
- X register struct dirent *dp;
- X
- X /* See whether the matching entry is in the current buffer. */
- X
- X if ((dirp->dd_loc < dirp->dd_size /* valid index */
- X || readdir(dirp) != NULL /* next buffer read */
- X && (dirp->dd_loc = 0, true) /* beginning of buffer set */
- X )
- X && (dp = (struct dirent *) & dirp->dd_buf[dirp->dd_loc])->d_off
- X <= loc /* match possible in this buffer */
- X ) {
- X for ( /* dp initialized above */ ;
- X (char *) dp < &dirp->dd_buf[dirp->dd_size];
- X dp = (struct dirent *) ((char *) dp + dp->d_reclen)
- X )
- X if (dp->d_off == loc) { /* found it! */
- X dirp->dd_loc =
- X (char *) dp - dirp->dd_buf;
- X return;
- X }
- X rewind = false; /* no point in backing up later */
- X dirp->dd_loc = dirp->dd_size; /* set end of buffer */
- X } else
- X /* whole buffer past matching entry */ if (!rewind) { /* no point in searching
- X * further */
- X errno = EINVAL;
- X return; /* no entry at specified loc */
- X } else { /* rewind directory and start over */
- X rewind = false; /* but only once! */
- X
- X dirp->dd_loc = dirp->dd_size = 0;
- X
- X if (lseek(dirp->dd_fd, (OFFSET) 0, SEEK_SET)
- X != 0
- X )
- X return; /* errno already set (EBADF) */
- X
- X if (loc == 0)
- X return; /* save time */
- X }
- X }
- X}
- X
- X
- X/* telldir - report directory stream position
- X *
- X * DESCRIPTION
- X *
- X * Returns the offset of the next directory entry in the
- X * directory associated with dirp.
- X *
- X * NOTE: 4.nBSD directory compaction makes seekdir() & telldir()
- X * practically impossible to do right. Avoid using them!
- X *
- X * PARAMETERS
- X *
- X * DIR *dirp - stream from opendir()
- X *
- X * RETURNS
- X *
- X * Return offset of next entry
- X */
- X
- X
- X#ifdef __STDC__
- X
- XOFFSET telldir(DIR *dirp)
- X
- X#else
- X
- XOFFSET telldir(dirp)
- XDIR *dirp; /* stream from opendir() */
- X
- X#endif
- X{
- X if (dirp == NULL || dirp->dd_buf == NULL) {
- X errno = EFAULT;
- X return -1; /* invalid pointer */
- X }
- X if (dirp->dd_loc < dirp->dd_size) /* valid index */
- X return ((struct dirent *) & dirp->dd_buf[dirp->dd_loc])->d_off;
- X else /* beginning of next directory block */
- X return lseek(dirp->dd_fd, (OFFSET) 0, SEEK_CUR);
- X}
- X
- X
- X#ifdef UFS
- X
- X/*
- X The following routine is necessary to handle DIRSIZ-long entry names.
- X Thanks to Richard Todd for pointing this out.
- X*/
- X
- X
- X/* return # chars in embedded name */
- X
- X#ifdef __STDC__
- X
- Xstatic int NameLen(char *name)
- X
- X#else
- X
- Xstatic int NameLen(name)
- Xchar *name; /* -> name embedded in struct direct */
- X
- X#endif
- X{
- X register char *s; /* -> name[.] */
- X register char *stop = &name[DIRSIZ]; /* -> past end of name field */
- X
- X for (s = &name[1]; /* (empty names are impossible) */
- X *s != '\0' /* not NUL terminator */
- X && ++s < stop; /* < DIRSIZ characters scanned */
- X );
- X
- X return s - name; /* # valid characters in name */
- X}
- X
- X#else /* BFS || NFS */
- X
- Xextern int strlen();
- X
- X#define NameLen( name ) strlen( name ) /* names are always NUL-terminated */
- X
- X#endif
- X
- X#ifdef UNK
- Xstatic enum {
- X maybe, no, yes
- X} state = maybe;
- X
- X
- X/* sig_catch - used to catch signals
- X *
- X * DESCRIPTION
- X *
- X * Used to catch signals.
- X */
- X
- X/*ARGSUSED*/
- X
- X#ifdef __STDC__
- X
- Xstatic void sig_catch(int sig)
- X
- X#else
- X
- Xstatic void sig_catch(sig)
- Xint sig; /* must be SIGSYS */
- X
- X#endif
- X{
- X state = no; /* attempted _getdents() faulted */
- X}
- X#endif
- X
- X
- X/* getdents - get directory entries
- X *
- X * DESCRIPTION
- X *
- X * Gets directory entries from the filesystem in an implemenation
- X * defined way.
- X *
- X * PARAMETERS
- X *
- X * int fildes - directory file descriptor
- X * char *buf - where to put the (struct dirent)s
- X * unsigned nbyte - size of buf[]
- X *
- X * RETURNS
- X *
- X * Returns number of bytes read; 0 on EOF, -1 on error
- X */
- X
- X#ifdef __STDC__
- X
- Xint getdents(int fildes, char *buf, unsigned nbyte)
- X
- X#else
- X
- Xint getdents(fildes, buf, nbyte)
- Xint fildes; /* directory file descriptor */
- Xchar *buf; /* where to put the (struct dirent)s */
- Xunsigned nbyte; /* size of buf[] */
- X
- X#endif
- X{
- X int serrno; /* entry errno */
- X OFFSET offset; /* initial directory file offset */
- X struct stat statb; /* fstat() info */
- X union {
- X /* directory file block buffer */
- X#ifdef UFS
- X char dblk[DIRBLKSIZ + 1];
- X#else
- X char dblk[DIRBLKSIZ];
- X#endif
- X struct direct dummy; /* just for alignment */
- X } u; /* (avoids having to malloc()) */
- X register struct direct *dp; /* -> u.dblk[.] */
- X register struct dirent *bp; /* -> buf[.] */
- X
- X#ifdef UNK
- X switch (state) {
- X SIG_T (*shdlr)(); /* entry SIGSYS handler */
- X register int retval; /* return from _getdents() if any */
- X
- X case yes: /* _getdents() is known to work */
- X return _getdents(fildes, buf, nbyte);
- X
- X case maybe: /* first time only */
- X shdlr = signal(SIGSYS, sig_catch);
- X retval = _getdents(fildes, buf, nbyte); /* try it */
- X signal(SIGSYS, shdlr);
- X
- X if (state == maybe) { /* SIGSYS did not occur */
- X state = yes; /* so _getdents() must have worked */
- X return retval;
- X }
- X /* else fall through into emulation */
- X
- X/* case no: /* fall through into emulation */
- X }
- X#endif
- X
- X if (buf == NULL
- X#ifdef ATT_SPEC
- X || (unsigned long) buf % sizeof(long) != 0 /* ugh */
- X#endif
- X ) {
- X errno = EFAULT; /* invalid pointer */
- X return -1;
- X }
- X if (fstat(fildes, &statb) != 0) {
- X return -1; /* errno set by fstat() */
- X }
- X
- X if (!S_ISDIR(statb.st_mode)) {
- X errno = ENOTDIR; /* not a directory */
- X return -1;
- X }
- X if ((offset = lseek(fildes, (OFFSET) 0, SEEK_CUR)) < 0) {
- X return -1; /* errno set by lseek() */
- X }
- X
- X#ifdef BFS /* no telling what remote hosts do */
- X if ((unsigned long) offset % DIRBLKSIZ != 0) {
- X errno = ENOENT; /* file pointer probably misaligned */
- X return -1;
- X }
- X#endif
- X
- X serrno = errno; /* save entry errno */
- X
- X for (bp = (struct dirent *) buf; bp == (struct dirent *) buf;) {
- X
- X /* convert next directory block */
- X int size;
- X
- X do {
- X size = GetBlock(fildes, u.dblk, DIRBLKSIZ);
- X } while (size == -1 && errno == EINTR);
- X
- X if (size <= 0) {
- X return size; /* EOF or error (EBADF) */
- X }
- X
- X for (dp = (struct direct *) u.dblk;
- X (char *) dp < &u.dblk[size];
- X dp = (struct direct *) ((char *) dp + RecLen(dp))
- X ) {
- X#ifndef UFS
- X if (dp->d_reclen <= 0) {
- X errno = EIO; /* corrupted directory */
- X return -1;
- X }
- X#endif
- X
- X if (dp->d_fileno != 0) { /* non-empty; copy to user buffer */
- X register int reclen =
- X DIRENTSIZ(NameLen(dp->d_name));
- X
- X if ((char *) bp + reclen > &buf[nbyte]) {
- X errno = EINVAL;
- X return -1; /* buf too small */
- X }
- X bp->d_ino = dp->d_fileno;
- X bp->d_off = offset + ((char *) dp - u.dblk);
- X bp->d_reclen = reclen;
- X
- X {
- X#ifdef UFS
- X /* Is the following kludge ugly? You bet. */
- X
- X register char save = dp->d_name[DIRSIZ];
- X /* save original data */
- X
- X dp->d_name[DIRSIZ] = '\0';
- X /* ensure NUL termination */
- X#endif
- X /* adds NUL padding */
- X strncpy(bp->d_name, dp->d_name, reclen - DIRENTBASESIZ);
- X#ifdef UFS
- X dp->d_name[DIRSIZ] = save;
- X /* restore original data */
- X#endif
- X }
- X
- X bp = (struct dirent *) ((char *) bp + reclen);
- X }
- X }
- X
- X#ifndef BFS /* 4.2BSD screwed up; fixed in 4.3BSD */
- X if ((char *) dp > &u.dblk[size]) {
- X errno = EIO; /* corrupted directory */
- X return -1;
- X }
- X#endif
- X }
- X
- X errno = serrno; /* restore entry errno */
- X return (char *) bp - buf; /* return # bytes read */
- X}
- END_OF_paxdir.c
- if test 16936 -ne `wc -c <paxdir.c`; then
- echo shar: \"paxdir.c\" unpacked with wrong size!
- fi
- # end of overwriting check
- fi
- echo shar: End of archive 5 \(of 6\).
- cp /dev/null ark5isdone
- MISSING=""
- for I in 1 2 3 4 5 6 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have unpacked all 6 archives.
- rm -f ark[1-9]isdone
- else
- echo You still need to unpack the following archives:
- echo " " ${MISSING}
- fi
- ## End of shell archive.
- exit 0
-
-